package ynet

import (
	"fmt"
	"golang-zinx-demo/yanx/utils"
	"golang-zinx-demo/yanx/yiface"
	"net"
)

// IServer的接口实现，定义一个Server的服务器模块
type Server struct {
	// 服务器的名称
	Name string
	// 服务器绑定的IP版本
	IPVersion string
	// 服务器监听的IP
	IP string
	// 服务器监听的端口
	Port int
	// 当前的Server的消息管理模块，用来绑定MsgID和对应的处理业务API
	MsgHandler yiface.IMsgHandle
	// 该server的连接管理器
	ConnMgr yiface.IConnManager
	// 该server创建之后自动调用的hook函数--OnConnStart
	OnConnStart func(conn yiface.IConnection)
	// 该server销毁之后自动调用的hook函数--OnConnStop
	OnConnStop func(conn yiface.IConnection)
}

// 开启服务器
func (s *Server) Start() {
	fmt.Printf("[Yanx] Server Name ：%s，listener at IP：%s，Port：%d is starting！\n",
		utils.GlobalObject.Name, utils.GlobalObject.Host, utils.GlobalObject.TCPPort)

	fmt.Printf("[Yanx] Version %s，MaxConn：%d，MamPackageSize：%d\n",
		utils.GlobalObject.Version, utils.GlobalObject.MaxConn, utils.GlobalObject.MaxPackageSize)

	go func() {
		// 0 开启消息队列及Worker工作池
		s.MsgHandler.StartWokerPool()

		// 1 获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addr error：", err)
			return
		}
		// 2 监听服务器的地址
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen:", s.IPVersion, " err: ", err)
			return
		}
		fmt.Println("Start Yanx server success, ", s.Name, " listenning...")

		var cid uint32
		cid = 0
		// 3 阻塞等待客户端的链接，处理客户端链接业务（读写）
		for {
			// 如果有客户端链接过来 阻塞会返回
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Println("AcceptTCP err", err)
				continue
			}

			// 判断最大连接个数，如果超过了服务器承载能力就直接关闭新连接
			if s.ConnMgr.Len() >= utils.GlobalObject.MaxConn {
				// TODO 给客户端相应一个超出最大连接数的错误包
				fmt.Println("=============》》》》Too Many Connections Overflow MaxConn: ",
					utils.GlobalObject.MaxConn)
				conn.Close()
				continue
			}

			// 将处理新链接的业务方法 和 conn 进行绑定 得到我们的链接模块
			dealConn := NewConnection(s, conn, cid, s.MsgHandler)
			cid++

			// 启动当前的链接业务处理
			go dealConn.Start()
		}
	}()
}

// 停止服务器
func (s *Server) Stop() {
	// 将一些服务器的资源、状态或者一些已经开辟的链接信息 进行停止或者回收
	fmt.Println("[Stop] Yanx server name: ", s.Name)
	s.ConnMgr.CLearConn()
}

// 运行服务器
func (s *Server) Serve() {
	// 启动server的服务功能
	s.Start()

	// TODO 做一下启动服务器之后的额外业务

	// 阻塞状态
	select {}

}

// 路由功能：给当前的服务注册一个路由方法，供客户端的链接处理使用
func (s *Server) AddRouter(msgID uint32, router yiface.IRouter) {
	s.MsgHandler.AddRouter(msgID, router)
	fmt.Println("AddRouter Success!!!")
}

// 注册OnConnStart钩子函数的方法
func (s *Server) SetOnConnStart(hookFunc func(conn yiface.IConnection)) {
	s.OnConnStart = hookFunc
}

// 注册OnConnStop钩子函数的方法
func (s *Server) SetOnConnStop(hookFunc func(conn yiface.IConnection)) {
	s.OnConnStop = hookFunc
}

// 调用OnConnStart钩子函数的方法
func (s *Server) CallOnConnStart(conn yiface.IConnection) {
	if s.OnConnStart != nil {
		s.OnConnStart(conn)
	}
}

// 调用OnConnStop钩子函数的方法
func (s *Server) CallOnConnStop(conn yiface.IConnection) {
	if s.OnConnStop != nil {
		s.OnConnStop(conn)
	}
}

func NewServer(name string) yiface.IServer {
	s := &Server{
		Name:       utils.GlobalObject.Name,
		IPVersion:  "tcp4",
		IP:         utils.GlobalObject.Host,
		Port:       utils.GlobalObject.TCPPort,
		MsgHandler: NewMsgHandle(),
		ConnMgr:    NewConnManager(),
	}
	return s
}
